package org.quipu.domain;

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.UniqueConstraint;

@Entity
@Table(name = "ACCOUNT", uniqueConstraints = {
    @UniqueConstraint(columnNames = {"ID_BOOK", "TITLE"}),
    @UniqueConstraint(columnNames = {"ID_DEBT"})})
@NamedQueries({
    @NamedQuery(name = "Account.findAll", query = "SELECT a FROM Account a"),
    @NamedQuery(name = "Account.findById", query = "SELECT a FROM Account a WHERE a.id=:id"),
    @NamedQuery(name = "Account.bindByTitleForBook", query = "SELECT a FROM Account a WHERE a.title=:title AND a.book.id=:bookId")
})
public class Account extends UniqueEntity implements Serializable {

    @JoinColumn(name = "ID_BOOK", referencedColumnName = "ID", nullable = false)
    @ManyToOne
    private Book book;

    @Column(name = "TITLE", length = 64, nullable = false)
    private String title;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "ID_DEBT", referencedColumnName = "ID", nullable = true)
    private Debt debt;

    @OneToMany(mappedBy = "srcAccount", cascade = CascadeType.REMOVE)
    private Collection<Transaction> outTransactions;

    @OneToMany(mappedBy = "dstAccount", cascade = CascadeType.REMOVE)
    private Collection<Transaction> inTransactions;

    @Column(name = "CREATION_DATE", nullable = false)
    @Temporal(javax.persistence.TemporalType.DATE)
    private Date creationDate;

    public Book getBook() {
        return book;
    }

    public void setBook(Book book) {
        this.book = book;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public boolean isThirdParty() {
        return debt != null;
    }

    public Debt getDebt() {
        return debt;
    }

    public void setDebt(Debt debt) {
        this.debt = debt;
    }

    public Collection<Transaction> getInTransactions() {
        return inTransactions;
    }

    public void setInTransactions(Collection<Transaction> inTransactions) {
        this.inTransactions = inTransactions;
    }

    public Collection<Transaction> getOutTransactions() {
        return outTransactions;
    }

    public void setOutTransactions(Collection<Transaction> outTransactions) {
        this.outTransactions = outTransactions;
    }

    public Collection<Transaction> getIncomes() {
        Collection<Transaction> incomes = new LinkedList<Transaction>();
        for(Transaction income: getInTransactions()) {
            if(income.getCategory() != null)
                incomes.add(income);
        }
        return incomes;
    }

    public Collection<Transaction> getOutcomes() {
        Collection<Transaction> outcomes = new LinkedList<Transaction>();
        for(Transaction outcome: getOutTransactions()) {
            if(outcome.getCategory() != null)
                outcomes.add(outcome);
        }
        return outcomes;
    }

    public Collection<Transaction> getInitialIncomes() {
        Collection<Transaction> initialIncome = new LinkedList<Transaction>();
        for(Transaction income: getInTransactions()) {
            if(income.getCategory() == null && income.getSrcAccount() == null)
                initialIncome.add(income);
        }
        return initialIncome;
    }

    public Collection<Transaction> getTransfers() {
        Collection<Transaction> transfers = new LinkedList<Transaction>();
        for(Transaction income: getInTransactions()) {
            if(income.getCategory() == null && income.getSrcAccount() != null)
                transfers.add(income);
        }
        for(Transaction outcome: getOutTransactions()) {
            if(outcome.getCategory() == null && outcome.getDstAccount() != null)
                transfers.add(outcome);
        }
        return transfers;
    }

    public Date getCreationDate() {
        return creationDate;
    }

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }

    @Override
    public String toString() {
        return "{Account: id=" + getId() + ", title=" + getTitle() + "}";
    }
}
